package de.aeo.bll;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author Frederic Branczyk & Robert Piwonski
 */
public class Algorithm{
    private int absoluteMin;
    private int standardMin;
    private ArrayList<Integer> bestCombination;
    private ArrayList<ArrayList<Course>> courses;
    private ArrayList<Course> courseList;
    private Manager m;
    private int value;
    private int alternativeValue;
    
    // Constructor
    /** Creates a new business layer with standard values.
     * 
     */
    public Algorithm(){
        // Weight can be changed by developers
        this.value = 1;
        this.alternativeValue = 0;
        this.m = new Manager();
        this.standardMin = 10000; // Value that will never be risen, so there will always be a solution
        this.bestCombination = new ArrayList<Integer>();
        this.courseList = new ArrayList<Course>();
    }
    
    public String getLanguageString(String s) {
        return this.m.getLanguage().getString(s);
    }
    
    /**
     * Detect the duration of the wished primary subjects.
     * @param st Student to be regarded.
     * @return Time that the 1,2,3 or 4 wished subjects amount to.
     */
    public int studentsSubjectTime(Student st) {
        int time = 0;
        Subject[] studentSubjects= st.getSubjectList();
        for(int i = 0; i < 4; i++){
            if(studentSubjects[i]!=null) 
                time += studentSubjects[i].getPeriod();     
        }
        return time;
    }
    
    /**
     * Detects how many courses the student is in.
     * @param st Student to be regarded.
     * @return Sum of courses student is in.
     */
    public int studentsCourseTime(Student st) {
        int time = 0;
        Course[] studentCourse= st.getCourseList();
        for(int i = 0; i < 4; i++){
            if(studentCourse[i]!=null){
                time++;
            }    
        }
        return time;
    }
    /**
     * 
     * @return
     */
    public ArrayList<Integer> timeCheck() {
        int a1 = 0;
        ArrayList<Integer> improperStudents = new ArrayList <Integer>();
        ArrayList<Student> studentList = this.m.getStudentList();
        for(Student st : studentList){
            if(studentsSubjectTime(st) != 4){
                improperStudents.add(a1);
            }
            a1++;
        }
        return improperStudents;
    }
    /**
     * Takes all the subjects and creates courses out of them, including their members.
     */
    public void createInitialCourseList() {
        ArrayList<Student> studentList = this.m.getStudentList();
        ArrayList<Subject> subjectList = this.m.getSubjectList();
        ArrayList<ArrayList<Course>> schedule = new ArrayList<ArrayList<Course>>();
        ArrayList<Course> overfilled = new ArrayList<Course>();
        schedule.add(new ArrayList<Course>());
        schedule.add(new ArrayList<Course>());
        schedule.add(new ArrayList<Course>());
        schedule.add(new ArrayList<Course>());
        // Sort the chosen subjects of the students so that 2-year-subject
        // Use of bubblesort since there are just 4 elements to be sorted,
        // in most cases they are already sorted, anyway.
        for(Student st : studentList){
            for(int i = 0;i < st.getCourseList().length-2; i++){
                for(int a = 0; a < st.getCourseList().length-2; a++){
                    if(st.getSubjectList()[a] != null && st.getSubjectList()[a+1] != null){
                        if(st.getSubjectList()[a].getPeriod() < st.getSubjectList()[a+1].getPeriod()){
                            Subject[] buffer = st.getSubjectList();
                            Subject buffer1 = buffer[a];
                            Subject buffer2 = buffer[a+1];
                            buffer[a] = buffer2;
                            buffer[a+1] = buffer1;
                            st.setSubjectList(buffer);
                        }
                    }
                }
            }
        }
        for(Subject s : subjectList) {
            ArrayList<Student> courseStudents = new ArrayList<Student>();
            ArrayList<Student> altStudents = new ArrayList<Student>();
            for(Student st : studentList) {
                for(int i=0; i<4; i++) {
                    if(s == st.getSubjectList()[i]) {
                        courseStudents.add(st);
                    }
                    
                }
                for(int i=4; i<6; i++) {
                    if(s == st.getSubjectList()[i]) {
                        altStudents.add(st);
                    }
                    
                }
            }            
            if(!courseStudents.isEmpty()){
                if(s.getPeriod() == 1){
                    schedule.get(0).add(new Course(courseStudents, altStudents, s.toString(), 0, s));
                }
                else{
                    // Link 2 year courses
                    Course first = new Course(courseStudents, altStudents, s.toString(), 1, s);
                    Course second = new Course(courseStudents, altStudents, s.toString(), 2, s);
                    first.setTwin(second);
                    second.setTwin(first);
                    schedule.get(0).add(first);
                    schedule.get(0).add(second);
                }
            }
        }
        // Sort all the overfilled and below minimum courses out
        for(int a = 0; a < schedule.size(); a++) {
            for(int i = 0; i < schedule.get(a).size(); i++) {
                    if((schedule.get(a).get(i).getStudentList().size() > schedule.get(a).get(i).getSubject().getMaxStudents()) || (schedule.get(a).get(i).getStudentList().size() < schedule.get(a).get(i).getSubject().getMinStudents())){
                        overfilled.add(schedule.get(a).get(i));
                    }
            }
        }
        for(Course of : overfilled){
            for(int a = 0; a < schedule.size(); a++) {
                    schedule.get(a).remove(of);

            }
        }
        this.m.setStudentList(studentList);
        this.m.setSchedule(schedule);
        this.m.setOverfilled(overfilled);      
    }
    /**
     * Moves a course from one layer to another
     * @param layer layer index of the course to be moved
     * @param element index on the original layer
     * @param direction -1 = left, 1 = right
     */
    public void moveCourse(int layer, int element, int direction){
        ArrayList<ArrayList<Course>> schedule = this.m.getSchedule();    
        Course toBeMoved = schedule.get(layer).get(element);
        if(toBeMoved.getChangeable()){
            // Is this movement valid ?
            // 2 year courses may not cross the middle, may not jump from one year to another
            if(toBeMoved.getTime() == 0 || (toBeMoved.getTime() == 1 && layer == 0) || (toBeMoved.getTime() == 1 && layer == 1 && direction == -1) || (toBeMoved.getTime() == 2 && layer == 3) || (toBeMoved.getTime() == 2 && layer == 2 && direction == 1)){
                schedule.get(layer).remove(element);
                schedule.get(layer+direction).add(toBeMoved);
            }
            this.m.setSchedule(schedule);
        }
    }
     
    /**
     * Creates the best possible schedule by trying out everything.
     * @return The new schedule.
     */
    public ArrayList<ArrayList<Course>> combination() {
        // reset everything
        bestCombination.clear();
        courses = this.m.getSchedule();
        absoluteMin = standardMin;
        // Add all course to one big list
        for(ArrayList<Course> cl : courses){
            for(Course c : cl){
                courseList.add(c);
            }
        }
        // Those combinations are valid :
        ArrayList<Integer> allYear = new ArrayList<Integer>();    
        ArrayList<Integer> yearOne = new ArrayList<Integer>();
        ArrayList<Integer> yearTwo = new ArrayList<Integer>();
        allYear.add(0);
        allYear.add(1);
        allYear.add(2);
        allYear.add(3);
        yearOne.add(0);
        yearOne.add(1);
        yearTwo.add(2);
        yearTwo.add(3);
        ArrayList<Course> sorted = new ArrayList<Course>();
        ArrayList<Course> firstYearCourses = new ArrayList<Course>();
        ArrayList<Course> secondYearCourses = new ArrayList<Course>();
        // Split between courses that may take place in the first year, second year
        // or it-doesn't-matter-which-year
        for(Course c : courseList){
            if(c.getTime() == 0){
                sorted.add(c);
            }
            else{
               if(c.getTime() == 1){ 
                firstYearCourses.add(c);
                }
                else{ 
                secondYearCourses.add(c);
                }
            }
        }
        // Start trying out combinations
        permutate(allYear, sorted, bestCombination, 0);
        absoluteMin = standardMin;
        // Remember the courses order
        for(Course c : firstYearCourses){
            sorted.add(c);
        }
        // Then add the courses from year one
        permutate(yearOne, sorted, bestCombination, 0);
        absoluteMin = standardMin;
        for(Course c : secondYearCourses){
            sorted.add(c);
        }
        // And those for year two
        permutate(yearTwo, sorted, bestCombination, 0);  
        // Match the best order along the course order
        ArrayList<ArrayList<Course>> finalCombination = new ArrayList<ArrayList<Course>>();
        finalCombination.add(new ArrayList<Course>());
        finalCombination.add(new ArrayList<Course>());
        finalCombination.add(new ArrayList<Course>());
        finalCombination.add(new ArrayList<Course>());
            for(int i = 0; i < sorted.size(); i++){
                             finalCombination.get(bestCombination.get(i)).add(sorted.get(i));
            }
            // Return the perfect schedule
            return finalCombination;
    }

    /**
     * Creates permutations in order to find the best combination
     * @param time Possible layers for the course
     * @param courses List of courses to be regarded
     * @param yet A list of combination that gets extended recursively, contains combinations.
     * @param min Number of overlaps up to now
     */
    public void permutate(ArrayList<Integer> time, ArrayList<Course> courses, ArrayList<Integer> yet, int min) {
                 if(!yet.isEmpty()){
                     int layer = yet.get((yet.size()-1));
                     ArrayList<Course> coursesAtLayer = new ArrayList<Course>();
                     for(int u = 0; u < yet.size()-1; u++){
                        if(yet.get(u) == layer){
                         coursesAtLayer.add(courses.get(u));
                        } 
                     }
                     Course newCourse = courses.get(yet.size()-1);
                     ArrayList<Student> addedStudents = newCourse.getStudentList();
                     // Has the student another course in this layer ?
                     for(Student newStudent : addedStudents){
                         boolean alreadyThere = false;
                         boolean alreadyThereAlt = false;
                         for(Course currentCourse : coursesAtLayer){
                             
                             if(currentCourse.getStudentList().contains(newStudent)){
                                 alreadyThere = true;
                                 if(alreadyThereAlt)
                                 break;
                             }
                             if(currentCourse.getAlt().contains(newStudent)){
                                    if(alreadyThere)
                                    break;
                             }
                         }                                             
                        if(alreadyThere)
                        min += value; 
                        if(alreadyThere)
                        min += alternativeValue;
                     }
                 }
      // Go on if this solution can get better than what has been already found.
      // Stop if this won't be better, anyway.
      if(min < absoluteMin){

// Has a possible solution been found ?
             if(yet.size() == courses.size()){
                // This is the best solution, yet
                absoluteMin = min;
                // Create copy
                ArrayList<Integer> possibleSolution= new ArrayList<Integer>();
                for(int i : yet){
                    possibleSolution.add(i);
                }
                this.bestCombination = possibleSolution;
                // Stop
                return;
             }
             for (int i : time){
                   yet.add(i);
                   permutate(time, courses, yet, min);
                   yet.remove(yet.size()-1);
             }
       }
   }
    /**
     * Gives the user the best layers to split a course on.
     * @param c The course to be split.
     * @return The best layer numbers in a list.
     */
    public ArrayList<Integer> suggestion(Course c){
            ArrayList<ArrayList<Course>> finishedCourses = m.getSchedule();
            int[] layers = new int[4];
            ArrayList<Student> students = c.getStudentList();
            // Counts overlaps
            for(Student st : students){
                for(int a = 0; a < finishedCourses.size(); a++){
                    ArrayList<Course> currentLayer = finishedCourses.get(a);
                    boolean alreadyThere = false;
                    boolean alreadyThereAlt = false;
                    for(Course co : currentLayer){
                        if(co.getStudentList().contains(st)){
                            alreadyThere = true;  
                            if(alreadyThereAlt)
                                break;
                        }
                        if(co.getAlt().contains(st)){
                             alreadyThereAlt = true;
                             if(alreadyThere)
                                 break;
                        }
                      
                    if(alreadyThere)
                        layers[a] += value;
                    if(alreadyThereAlt)
                        layers[a] += alternativeValue;
                    }
                }
            }
            // Match the best combinations to the best layers
            int[] unSorted = {layers[0],layers[1],layers[2],layers[3]};
            ArrayList<Integer> suitableLayers = new ArrayList<Integer>();
            Arrays.sort(layers);
            for(int i = 0; i < 4; i++){
                for(int a = 0; a < layers.length; a++){
                    if(layers[i] == unSorted[a] ){
                        if((c.getTime() == 0) || (c.getTime() == 1 && (a ==0 || a ==1))|| (c.getTime() == 2 && (a ==2 || a ==3))){
                            suitableLayers.add(a);    
                        }
                        else{
                            suitableLayers.add(-1);
                        }
                        
                        unSorted[a] = 50; // Not regarded anymore
                    }
                }
            }

            return suitableLayers;
    }
    /**
     * Splits a course on the given layers. Splits twice if the course takes place both years.
     * @param c Course to be split.
     * @param suitableLayers Layers the course will be moved onto.
     * @return A new schedule with the new courses on it.
     */
    public ArrayList<ArrayList<Course>> splitCourse(Course c, ArrayList<Integer> suitableLayers){
        ArrayList<ArrayList<Course>> finishedCourses = m.getSchedule();
        ArrayList<Student> students = c.getStudentList();
        ArrayList<ArrayList<Student>> busyStudents = new ArrayList<ArrayList<Student>>();
        busyStudents.add(new ArrayList<Student>());
        busyStudents.add(new ArrayList<Student>());       
        busyStudents.add(new ArrayList<Student>());
        busyStudents.add(new ArrayList<Student>());
        ArrayList<ArrayList<Student>> suitableStudents = new ArrayList<ArrayList<Student>>();
        suitableStudents.add(new ArrayList<Student>());
        suitableStudents.add(new ArrayList<Student>());       
        suitableStudents.add(new ArrayList<Student>());
        suitableStudents.add(new ArrayList<Student>());
        // Only add suitable students, otherwise the next
        // suggestion might not be appropiate or in vain if all splittet courses contain the same students
        for(Student st : students){
            int i = 0;
            for(int a : suitableLayers){
                ArrayList<Course> currentLayer = finishedCourses.get(a);
                for(Course co : currentLayer){
                    if(co.getStudentList().contains(st)){
                        busyStudents.get(i).add(st);                        
                    }
                }
                i++; 
            }
        }
        for(int i = 0; i < suitableLayers.size(); i++){
            for(Student st : students){
                    if(!busyStudents.get(i).contains(st)){                        
                        suitableStudents.get(i).add(st);
                    }
            }            
        } 
        ArrayList<Course> withoutOldCourse = this.m.getOverfilled();
        if(c.getTime()==0){
            for(int i = 0; i < suitableLayers.size(); i++){
                Course newCourse = new Course(suitableStudents.get(suitableLayers.get(i)), c.getSubject().getName()+"."+(i+1), c.getTime(), c.getSubject());
                finishedCourses.get(suitableLayers.get(i)).add(newCourse);
            }
            withoutOldCourse.remove(c);
        }
        else{
                    for(int i = 0; i < suitableLayers.size(); i++){
                Course newCourse = new Course(suitableStudents.get(suitableLayers.get(i)), c.getSubject().getName()+"."+(i+1), c.getTime(), c.getSubject());
                Course twin = new Course(suitableStudents.get(suitableLayers.get(i)), c.getSubject().getName()+"."+(i+1), c.getTwin().getTime(), c.getSubject());
                newCourse.setTwin(twin);
                twin.setTwin(newCourse);
                finishedCourses.get(suitableLayers.get(i)).add(newCourse);
                if(suitableLayers.get(i) == 0 || suitableLayers.get(i) == 1){
                    finishedCourses.get(suitableLayers.get(i)+2).add(twin);
                }
                else{
                    finishedCourses.get(suitableLayers.get(i)-2).add(twin);
                }
                
            }
            withoutOldCourse.remove(c);
            withoutOldCourse.remove(c.getTwin());
        
        }
        this.m.setOverfilled(withoutOldCourse);
        return finishedCourses;
    }
    
    /**
     * Counts the maximum overlaps.
     * @return The total overlap of students.
     */
    public int countOverlap(){
           ArrayList<Student> studentList = this.m.getStudentList();
           ArrayList<ArrayList<Course>> schedule = this.m.getSchedule();
           int overlap = 0;
           for(Student st : studentList){
                int overlaped = 0;
                for(ArrayList<Course> clist : schedule){
                  int appearance = 0;  
                  for(Course c : clist){
                            if(c.getStudentList().contains(st)){
                                appearance++;
                            }
                  } 
                   if(appearance > 1){
                    overlaped = 1;
                    break;
                   }
                }
                overlap += overlaped;
            }            
           return overlap;
        }
    
    /**
     * Sorts all the students into their courses and checks whether the fit or not. 
     */
    public void finish(){ 
           ArrayList<Student> studentList = this.m.getStudentList();
           ArrayList<Student> ready = new ArrayList<Student>();
           ArrayList<Student> readyA = new ArrayList<Student>();
           ArrayList<ArrayList<Course>> schedule = this.m.getSchedule();
           // Clear all course membership in order to prepare them for the new ones.
           for(ArrayList<Course> cl :schedule){
               for(Course c : cl){
                   c.setStudentList(new ArrayList<Student>());
               }
           }
           // Match all the possible courses on each layer that fit the students primary and secondary
           // wishes.
           for(Student st : studentList){
                ArrayList<ArrayList<Course>> coursesAtLayer = new ArrayList<ArrayList<Course>>();
                ArrayList<ArrayList<Course>> altAtLayer = new ArrayList<ArrayList<Course>>();
                coursesAtLayer.add(new ArrayList<Course>());
                coursesAtLayer.add(new ArrayList<Course>());
                coursesAtLayer.add(new ArrayList<Course>());
                coursesAtLayer.add(new ArrayList<Course>());
                altAtLayer.add(new ArrayList<Course>());
                altAtLayer.add(new ArrayList<Course>());
                altAtLayer.add(new ArrayList<Course>());
                altAtLayer.add(new ArrayList<Course>());
                for(int su = 0; su < 4; su++){
                for(int layer = 0; layer < schedule.size(); layer++){
                    for(int a = 0; a < schedule.get(layer).size(); a++){
                        
                              if(schedule.get(layer).get(a).getSubject() == st.getSubjectList()[su]){
                                  coursesAtLayer.get(layer).add(schedule.get(layer).get(a));
                              } else{
                                  if(schedule.get(layer).get(a).getSubject() == st.getSubjectList()[4] || schedule.get(layer).get(a).getSubject() == st.getSubjectList()[5]){
                                    altAtLayer.get(layer).add(schedule.get(layer).get(a));
                                  }
                              }
                          }

                      }    
                }
                st.setCoursesAtLayer(coursesAtLayer);
                st.setAltAtLayer(altAtLayer);
            }
           // Clear all the courses' student list since they well be refreshed. 
           for(ArrayList<Course> cl :schedule){
               for(Course c : cl){
                   c.setStudentList(new ArrayList<Student>());
               }
           }
           // First match the students that fit instantly, because they should be given an advantage.
           // Of course, this will be the least part.
            for(int i = 0; i < studentList.size(); i++){
                if(this.setSecure(studentList.get(i))){
                    Course [] coursesStudentIsIn = studentList.get(i).getCourseList();
                    for(int a = 0; a < coursesStudentIsIn.length; a++){
                        if(coursesStudentIsIn[a]!= null){
                            ArrayList<Student> newMemberList = coursesStudentIsIn[a].getStudentList();
                            newMemberList.add(studentList.get(i));
                            coursesStudentIsIn[a].setStudentList(newMemberList);
                        }
                    }
                    studentList.get(i).setState(0);
                    ready.add(studentList.get(i));
                }
            }
            // Remove the new course members from the other students, so they don't
            // get proven again (less repetition).
            for(Student st : ready){
                studentList.remove(st);
            }
            // Then match the students by the priority they voted.
            // This is most likely the majority.
            for(int i = 0; i < studentList.size(); i++){
                if(this.setWithPriority(studentList.get(i))){
                    Course [] coursesStudentIsIn = studentList.get(i).getCourseList();
                    for(int a = 0; a < coursesStudentIsIn.length; a++){
                        if(coursesStudentIsIn[a]!= null){
                            ArrayList<Student> newMemberList = coursesStudentIsIn[a].getStudentList();
                            newMemberList.add(studentList.get(i));
                            coursesStudentIsIn[a].setStudentList(newMemberList);
                        }
                    }
                    studentList.get(i).setState(0);
                    ready.add(studentList.get(i));
                }
            }
            // Remove the new course members from the other students, so they don't
            // get proven again (less repetition).
            for(Student st : ready){
                studentList.remove(st);
            }
            // Then match those who unfortunate didn't get all of their wishes
            for(int i = 0; i < studentList.size(); i++){
                if(this.setAlternative(studentList.get(i))){
                    Course [] coursesStudentIsIn = studentList.get(i).getCourseList();
                    for(int a = 0; a < coursesStudentIsIn.length; a++){
                        if(coursesStudentIsIn[a]!= null){
                            ArrayList<Student> newMemberList = coursesStudentIsIn[a].getStudentList();
                            newMemberList.add(studentList.get(i));
                            coursesStudentIsIn[a].setStudentList(newMemberList);
                        }
                    }
                    studentList.get(i).setState(1);
                    //ready.add(studentList.get(i));
                }
            }
            // Add all students to one big list
            for(Student st : ready){
                studentList.add(st);
            }
            this.m.setStudentList(studentList);
            this.m.setSchedule(schedule);
        }

    /**
     * Finds a given course and tells it's current position.
     * @param c Course to be found
     * @return Array of layer and element number
     */
    public int[] getPosition (Course c){
            ArrayList<ArrayList<Course>> schedule = this.m.getSchedule();
            for(int positiona = 0; positiona < schedule.size(); positiona++){
                for(int positionb = 0; positionb < schedule.get(positiona).size(); positionb++){
                    if(schedule.get(positiona).get(positionb) == c){
                        int[] position = new int[2];
                        position[0] = positiona;
                        position[1] = positionb;
                        return position;
                    }
                }
            }
            int[] wonthappen = new int[2];
            return wonthappen; // Won't happen, Course exsists for sure.
        }
        /**
         * Locks all courses so that they can't be messed with anymore.
         */
        public void setAllUnchangeable(){
            ArrayList<ArrayList<Course>> schedule = this.m.getSchedule();
            for(ArrayList<Course> cl : schedule){
                for(Course c : cl){
                    c.setUnChangeable();
                }
            }
            this.m.setSchedule(schedule);
        }
        
        /**
         * Tries to sort in a student. Only works if the student fits perfectly.
         * @param st Students to be sorted in.
         * @return True if students fits instantly. False if not.
         */
        public Boolean setSecure(Student st){               
                Course[] newCourseList = new Course[4];
                ArrayList<ArrayList<Course>> newCoursesAtLayer = st.getCoursesAtLayer();
                int neededTime = this.studentsSubjectTime(st);
                int timeAlready = 0; 
                for(int q = 0; q < newCoursesAtLayer.size(); q++){
                    for(int i = 0; i < newCoursesAtLayer.size(); i++){
                        boolean both = false;
                        // Are there still wishes to be fulfilled ?
                        if(newCourseList[i] == null && timeAlready < neededTime){
                            // Is it the only possible course ?
                            if(newCoursesAtLayer.get(i).size() == 1 && newCoursesAtLayer.get(i).get(0).getStudentList().size() < newCoursesAtLayer.get(i).get(0).getSubject().getMaxStudents()){
                            if(newCoursesAtLayer.get(i).get(0).getTime() != 0){
                                      int[] position = this.getPosition(newCoursesAtLayer.get(i).get(0).getTwin());
                                      if(newCourseList[position[0]] == null){  
                                          newCourseList[position[0]] = newCoursesAtLayer.get(i).get(0).getTwin();
                                          timeAlready++;
                                          newCourseList[i] = newCoursesAtLayer.get(i).get(0);
                                          timeAlready++;
                                          both  = true;
                                      }
                                      
                            }
                            else{
                                          newCourseList[i] = newCoursesAtLayer.get(i).get(0);
                                          timeAlready++;
                            }
                            if(newCourseList[i] != null){
                            if(both){
                            // Remove subject from all layers so it won't get picked again.
                                for(int a = 0; a < newCoursesAtLayer.size(); a ++){
                                    for(int b = 0; b < newCoursesAtLayer.get(a).size(); b++){
                                        if((newCoursesAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject())){
                                            newCoursesAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                                
                            }
                            else{
                                // Remove just subject when time is the same.    
                                for(int a = 0; a < newCoursesAtLayer.size(); a ++){
                                    for(int b = 0; b < newCoursesAtLayer.get(a).size(); b++){
                                        if((newCoursesAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject()) && (newCourseList[i].getTime() == newCoursesAtLayer.get(a).get(b).getTime())){
                                            newCoursesAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                            }
                            
                            }

                            }
                        }
                    }
               }   
               st.setCourseList(newCourseList);
               st.setCoursesAtLayer(newCoursesAtLayer);
               // Is this student ready ?
               if(timeAlready == neededTime){               
                   return true;
               }
               return false;                   
       }

        /**
         * Sorts a student in the schedule. Where there are two or more opportunities, one the one that works and was voted firstly.
         * @param st Student to be sorted in
         * @return True if student fit, false if not.
         */
        public Boolean setWithPriority(Student st){               
                Course[] newCourseList = st.getCourseList();
                ArrayList<ArrayList<Course>> newCoursesAtLayer = st.getCoursesAtLayer();
                int neededTime = this.studentsSubjectTime(st);
                int timeAlready = this.studentsCourseTime(st);
                for(int q = 0; q < newCoursesAtLayer.size(); q++){
                    for(int i = 0; i < newCoursesAtLayer.size(); i++){
                        boolean both = false;
                        // Are there still wishes to be fulfilled ?
                        if(newCourseList[i] == null && timeAlready < neededTime){
                            // Are there one or more possible courses ?
                            if(newCoursesAtLayer.get(i).size() >= 1){
                                for(int a = 0; a < newCoursesAtLayer.get(i).size(); a ++){    
                                if(newCoursesAtLayer.get(i).get(a).getStudentList().size() < newCoursesAtLayer.get(i).get(a).getSubject().getMaxStudents()){
                                    // If this subject takes 2 years, take both courses
                                    if(newCoursesAtLayer.get(i).get(a).getTwin() != null){
                                              int[] position = this.getPosition(newCoursesAtLayer.get(i).get(a).getTwin());
                                              if(newCourseList[position[0]] == null){  
                                                  newCourseList[position[0]] = newCoursesAtLayer.get(i).get(a).getTwin();
                                                  timeAlready++;
                                                  newCourseList[i] = newCoursesAtLayer.get(i).get(a);
                                                  timeAlready++;
                                                  both  = true;
                                              }
                                              else{
                                                  // Take the next suitable course
                                                  continue;
                                                          }

                                    }
                                    else{
                                                  newCourseList[i] = newCoursesAtLayer.get(i).get(a);
                                                  timeAlready++;
                                    }
                                    break;
                                }
                             }
                            if(newCourseList[i] != null){
                            if(both){
                            // Remove subject from all layers so it won't get picked again.
                                for(int a = 0; a < newCoursesAtLayer.size(); a ++){
                                    for(int b = 0; b < newCoursesAtLayer.get(a).size(); b++){
                                        if((newCoursesAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject())){
                                            newCoursesAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                                
                            }
                            else{
                                   for(int a = 0; a < newCoursesAtLayer.size(); a ++){
                                    for(int b = 0; b < newCoursesAtLayer.get(a).size(); b++){
                                        if((newCoursesAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject()) && (newCourseList[i].getTime() == newCoursesAtLayer.get(a).get(b).getTime())){
                                            newCoursesAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                            }
                            
                            }

                            }
                        }
                    }
               }   
               st.setCourseList(newCourseList);
               st.setCoursesAtLayer(newCoursesAtLayer);
               // Is this student ready ?
               System.out.println(st.getFirstname() + " " + st.getLastname() + " " + newCourseList[0]+newCourseList[1]+newCourseList[2]+newCourseList[3]);
               System.out.println(timeAlready+ " aber "+ this.studentsCourseTime(st));
               if(timeAlready == neededTime){               
                   return true;
               }
               return false;                   
       }             

        /**
         * Gives remaining students their alternative.
         * @param st Student that receives alternative subject.
         * @return True if student now has all of his subjects.
         */
        public Boolean setAlternative(Student st){               
                Course[] newCourseList = st.getCourseList();
                ArrayList<ArrayList<Course>> newCoursesAtLayer = st.getCoursesAtLayer();
                ArrayList<ArrayList<Course>> altAtLayer = st.getAltAtLayer();
                int neededTime = this.studentsSubjectTime(st);
                int timeAlready = this.studentsCourseTime(st);
                for(int q = 0; q < newCoursesAtLayer.size(); q++){
                    for(int i = 0; i < newCoursesAtLayer.size(); i++){
                        boolean both = false;
                        // Are there still wishes to be fulfilled ?
                        if(newCourseList[i] == null && timeAlready < neededTime){
                            // Is there an alternative for that layer ?
                            if(altAtLayer.get(i).size() >= 1){
                                for(int a = 0; a < altAtLayer.get(i).size(); a ++){    
                                if(altAtLayer.get(i).get(a).getStudentList().size() < altAtLayer.get(i).get(a).getSubject().getMaxStudents()){
                                    if(altAtLayer.get(i).get(a).getTwin() != null){
                                              int[] position = this.getPosition(altAtLayer.get(i).get(a).getTwin());
                                                System.out.println("Bebenkurs von "+altAtLayer.get(i).get(a)+"auf Schiene"+this.getPosition(altAtLayer.get(i).get(a))[0]+" ist" +altAtLayer.get(i).get(a).getTwin()+ "Auf Schiene "+position[0]);
                                              if(newCourseList[position[0]] == null){  
                                                  newCourseList[position[0]] = altAtLayer.get(i).get(a).getTwin();
                                                  timeAlready++;
                                                  newCourseList[i] = altAtLayer.get(i).get(a);
                                                  timeAlready++;
                                                  both  = true;
                                              }
                                              else{
                                                  continue;
                                                          }

                                    }
                                    else{
                                                  newCourseList[i] = altAtLayer.get(i).get(a);
                                                  timeAlready++;
                                    }
                                    break;
                                }
                             }
                            if(newCourseList[i] != null){
                            if(both){
                            // Remove subject from all layers so it won't get picked again.
                                for(int a = 0; a < altAtLayer.size(); a ++){
                                    for(int b = 0; b < altAtLayer.get(a).size(); b++){
                                        if((altAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject())){
                                            altAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                                
                            }
                            else{
                                                for(int a = 0; a < altAtLayer.size(); a ++){
                                    for(int b = 0; b < altAtLayer.get(a).size(); b++){
                                        if((altAtLayer.get(a).get(b).getSubject() == newCourseList[i].getSubject()) && (newCourseList[i].getTime() == altAtLayer.get(a).get(b).getTime())){
                                            altAtLayer.get(a).remove(b);
                                            b--;
                                        }
                                    }
                                }
                            }
                            
                            }

                            }
                        }
                    }
               }   
               st.setCourseList(newCourseList);
               st.setCoursesAtLayer(newCoursesAtLayer);
               // Is this student ready ?
               System.out.println(st.getFirstname() + " " + st.getLastname() + " " + newCourseList[0]+newCourseList[1]+newCourseList[2]+newCourseList[3]);
               System.out.println(timeAlready+ " aber "+ this.studentsCourseTime(st));
               if(timeAlready == neededTime){               
                   return true;
               }
               return false;                   
       }             
    public int getSubjectMinMin() {
        return this.m.getSubjectMinMin();
    }

    public int getSubjectMinMax() {
        return this.m.getSubjectMinMax();
    }

    public int getSubjectMaxMin() {
        return this.m.getSubjectMaxMin();
    }

    public int getSubjectMaxMax() {
        return this.m.getSubjectMaxMax();
    }

    public void addSubjectList(Subject s) {
        this.m.addSubjectList(s);
    }

    public int getSubjectCount() {
        return this.m.getSubjectCount();
    }

    public ArrayList<Subject> getSubjectList() {
        return this.m.getSubjectList();
    }

    public void addStudentList(Student s) {
        this.m.addStudentList(s);
    }

    public int getStudentCount() {
        return this.m.getStudentCount();
    }

    public void exportData(File selectedFile) throws FileNotFoundException, MalformedURLException {
        this.m.exportData(selectedFile);
    }

    public void importData(File selectedFile) throws ImproperDataException, MalformedURLException, IOException {
        this.m.importData(selectedFile);
    }

    public ArrayList<Student> getStudentList() {
        return this.m.getStudentList();
    }

    public void setLanguage(Language language) {
        this.m.setLanguage(language);
    }

    public ArrayList<Course> getOverfilled() {
        return this.m.getOverfilled();
    }

    public void setSchedule(ArrayList<ArrayList<Course>> s) {
        this.m.setSchedule(s);
    }

    public void setOverfilled(ArrayList<Course> arrayList) {
        this.m.setOverfilled(arrayList);
    }

    public ArrayList<ArrayList<Course>> getSchedule() {
        return this.m.getSchedule();
    }
    
    public void exportResultData() throws FileNotFoundException, IOException{
        this.m.exportResultData();
    }      
}